package com.hzlj.position.locate.dao;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Pair;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fz.common.base.converter.QueryWrapperConverterPlus;
import com.fz.common.base.core.JsonUtils;
import com.fz.common.base.core.db.function.IFUtil;
import com.fz.common.base.core.db.function.ToCharUtil;
import com.fz.common.base.core.db.function.ToNumberUtil;
import com.fz.common.base.dto.PageParamDTO;
import com.fz.common.base.dto.QueryPageResultDTO;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.hzlj.position.config.common.dto.common.PositionCommonDTO;
import com.hzlj.position.config.common.dto.common.PositionHandleExtDTO;
import com.hzlj.position.config.common.dto.common.PositionHandleQueryResultDTO;
import com.hzlj.position.config.common.enums.ReportType;
import com.hzlj.position.config.common.enums.WarningType;
import com.hzlj.position.locate.common.common.PositionWithExtDTO;
import com.hzlj.position.locate.common.common.PositionWithHandleDTO;
import com.hzlj.position.locate.common.common.ReadUpdateDTO;
import com.hzlj.position.locate.common.dto.position.*;
import com.hzlj.position.locate.common.enums.PositionCorrectStatus;
import com.hzlj.position.locate.common.model.Position;
import com.hzlj.position.locate.mapper.PositionMapper;
import com.hzlj.sqjz.config.common.dto.common.handle.HandleCommonExtDTO;
import com.hzlj.sqjz.jz.common.constant.JzJoin;
import com.hzlj.sqjz.jz.common.model.JzJbxx;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Repository;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;

/**
 * 定位记录-分表(Position)表操作类
 *
 * @author lifh
 * @date 2023-03-16 12:48:19
 */
@Slf4j
@Repository
public class PositionDao extends ServiceImpl<PositionMapper, Position> {
    @Resource
    private PositionMapper positionMapper;


    /**
     * 查询列表：不分页
     */
    public List<PositionWithExtDTO> listPositionWithExt(PositionQueryParamDTO dto) {
        return QueryWrapperConverterPlus.of(positionMapper)
                .list(PositionWithExtDTO.class, dto, q -> {
                    q.orderByAsc(Position::getPositionTime);
                    queryWrapper(dto, q);
                });
    }

    /**
     * 查询列表：不分页
     */
    public List<PositionCommonDTO> listPositionCommon(PositionQueryParamDTO dto) {
        return QueryWrapperConverterPlus.of(positionMapper)
                .list(PositionCommonDTO.class, dto, q -> {
                    q.orderByAsc(Position::getPositionTime);
                    queryWrapper(dto, q);
                });
    }


    public List<PositionWithHandleDTO> listPosition4Handle(PositionQueryParamDTO dto) {
        return QueryWrapperConverterPlus.of(positionMapper)
                .list(PositionWithHandleDTO.class, dto, q -> {
                    q.orderByAsc(Position::getPositionTime);
                    queryWrapper(dto, q);
                });
    }

    /**
     * 查询列表：不分页
     *
     * @param dto 查询条件
     * @return 对象列表
     */
    public PositionQueryResultDTO position(PositionQueryParamDTO dto) {
        return QueryWrapperConverterPlus.of(positionMapper)
                .innerJoin(Boolean.TRUE.equals(dto.getWithJzJbxx()), JzJbxx.class, JzJoin.jz(Position::getJzId))
                .selectOne(PositionQueryResultDTO.class, dto, null, q -> {
                    queryWrapper(dto, q);
                });
    }

    /**
     * 查询列表：不分页
     *
     * @param dto 查询条件
     * @return 对象列表
     */
    public List<PositionQueryResultDTO> listPosition(PositionQueryParamDTO dto) {
        return QueryWrapperConverterPlus.of(positionMapper)
                .innerJoin(Boolean.TRUE.equals(dto.getWithJzJbxx()), JzJbxx.class, JzJoin.jz(Position::getJzId))
                .list(PositionQueryResultDTO.class, dto, q -> {
                    queryWrapper(dto, q);
                });
    }

    /**
     * 查询列表：分页
     *
     * @param dto  查询条件
     * @param page 分页信息
     * @return 对象列表withJzJbxx
     */
    public QueryPageResultDTO<PositionQueryResultDTO> pagePosition(PositionQueryParamDTO dto, PageParamDTO page) {
        page.setSort(false);
        return QueryWrapperConverterPlus.of(positionMapper)
                .innerJoin(Boolean.TRUE.equals(dto.getWithJzJbxx()), JzJbxx.class, JzJoin.jz(Position::getJzId))
                .page(PositionQueryResultDTO.class, dto, page, q -> {
                    queryWrapper(dto, q);
                });
    }


    public PositionQueryResultDTO getPosition(String id, Date positionTime) {
        return QueryWrapperConverterPlus.of(positionMapper)
                .selectOne(PositionQueryResultDTO.class, null, null, q -> q
                        .eq(Position::getId, id)
                        .eq(Position::getPositionTime, positionTime)
                );
    }

    public PositionQuerySimpleResultDTO getSimplePosition(String id, Date positionTime) {
        return QueryWrapperConverterPlus.of(positionMapper)
                .selectOne(PositionQuerySimpleResultDTO.class, null, null, q -> q
                        .eq(Position::getId, id)
                        .eq(Position::getPositionTime, positionTime)
                );
    }


    public PositionHandleQueryResultDTO getHandleResult(String id, Date positionTime) {
        return QueryWrapperConverterPlus.of(positionMapper)
                .selectOne(PositionHandleQueryResultDTO.class, null, null, q -> q
                        .eq(Position::getId, id)
                        .eq(Position::getPositionTime, positionTime)
                );
    }

    public PositionHandleExtDTO getHandleResultExt(String id, Date positionTime) {
        String handleExt = QueryWrapperConverterPlus.of(positionMapper)
                .selectOneField(String.class, q -> q
                        .select(Position::getHandleExt)
                        .eq(Position::getId, id)
                        .eq(Position::getPositionTime, positionTime)
                );
        if (ObjectUtil.isNotEmpty(handleExt)) {
            return JsonUtils.json2obj(handleExt, PositionHandleExtDTO.class);
        }
        return null;
    }

    public PositionExtDTO getPositionExt(String id, Date positionTime) {
        String positionExt = QueryWrapperConverterPlus.of(positionMapper)
                .selectOneField(String.class, q -> q
                        .select(Position::getPositionExt)
                        .eq(Position::getId, id)
                        .eq(Position::getPositionTime, positionTime)
                );
        if (ObjectUtil.isEmpty(positionExt)) {
            return new PositionExtDTO();
        }
        PositionExtDTO ext = JsonUtils.json2obj(positionExt, PositionExtDTO.class);
        if (ObjectUtil.isEmpty(ext)) {
            log.warn("转换成PositionExt出错，请核实数据是否正确:id={},positionTime={},ext={}",
                    id, positionTime, positionExt);
            return new PositionExtDTO();
        }
        return ext;
    }


    public void handle(PositionHandleDTO dto) {
        Pair<Date, Date> dateDatePair = dto.minMaxPositionTimes();
        String warningType = ToCharUtil.format(ToNumberUtil.format("warning_type") + "+50");
        warningType = IFUtil.format("warning=1", warningType, "warning_type");
        LambdaUpdateWrapper<Position> updateWrapper = new UpdateWrapper<Position>().lambda()
                .set(Position::getUpdateTime, new Date())
                .set(Position::getHandleStatus, dto.getHandleStatus())
                .set(Position::getHandleTime, dto.getHandleTime())
                .set(ObjectUtil.isNotEmpty(dto.getHandleExt()), Position::getHandleExt, JsonUtils.obj2json(dto.getHandleExt()))
                .set(ObjectUtil.isNotEmpty(dto.getSysCheck()), Position::getSysCheck, dto.getSysCheck())
                .setSql(Boolean.TRUE.equals(dto.getNormal()), "warning_type=" + warningType)
                .set(Boolean.TRUE.equals(dto.getNormal()), Position::getWarning, false)
                .in(Position::getId, dto.ids())
                .ge(Position::getPositionTime, dateDatePair.getKey())
                .le(Position::getPositionTime, dateDatePair.getValue());
        this.update(updateWrapper);
    }

    public void handleSysCheck(PositionHandleDTO dto) {
        Pair<Date, Date> dateDatePair = dto.minMaxPositionTimes();
        LambdaUpdateWrapper<Position> updateWrapper = new UpdateWrapper<Position>().lambda()
                .set(Position::getUpdateTime, new Date())
                .set(Position::getSysCheck, dto.getSysCheck())
                .in(Position::getId, dto.ids())
                .ge(Position::getPositionTime, dateDatePair.getKey())
                .le(Position::getPositionTime, dateDatePair.getValue());
        this.update(updateWrapper);
    }

    public void read(ReadUpdateDTO dto) {
        LambdaUpdateWrapper<Position> updateWrapper = new UpdateWrapper<Position>().lambda()
                .set(Position::getRead, true)
                .set(Position::getReadTime, dto.getReadTime())
                .eq(Position::getId, dto.getId())
                .ge(Position::getPositionTime, DateUtil.beginOfDay(dto.getRecordTime()))
                .le(Position::getPositionTime, DateUtil.endOfDay(dto.getRecordTime()));
        this.update(updateWrapper);
    }


    public void updatePositionExt(String id,
                                  Date positionTime,
                                  PositionExtDTO positionExt) {
        LambdaUpdateWrapper<Position> updateWrapper = new UpdateWrapper<Position>().lambda()
                .set(Position::getPositionExt, JsonUtils.obj2json(positionExt))
                .eq(Position::getId, id)
                .eq(Position::getPositionTime, positionTime);
        this.update(updateWrapper);
    }


    public void updateCorrectStatus(String id,
                                    Date positionTime,
                                    PositionCorrectStatus status,
                                    PositionExtDTO positionExt) {
        LambdaUpdateWrapper<Position> updateWrapper = new UpdateWrapper<Position>().lambda()
                .set(Position::getCorrectStatus, status.getCode())
                .set(Position::getPositionExt, JsonUtils.obj2json(positionExt))
                .eq(Position::getId, id)
                .eq(Position::getPositionTime, positionTime);
        this.update(updateWrapper);
    }


    public void updateCorrectStatus(String id,
                                    Date positionTime,
                                    PositionCorrectStatus status,
                                    PositionExtDTO positionExt,
                                    Date handleTime,
                                    HandleCommonExtDTO handleExt) {
        LambdaUpdateWrapper<Position> updateWrapper = new UpdateWrapper<Position>().lambda()
                .set(Position::getCorrectStatus, status.getCode())
                .set(Position::getPositionExt, JsonUtils.obj2json(positionExt))
                .set(Position::getHandleTime, handleTime)
                .set(Position::getHandleExt, JsonUtils.obj2json(handleExt))
                .eq(Position::getId, id)
                .eq(Position::getPositionTime, positionTime);
        this.update(updateWrapper);
    }

    public void updateSyncStatus(String id,
                                 Date positionTime,
                                 String syncStatus,
                                 PositionExtDTO positionExt) {
        LambdaUpdateWrapper<Position> updateWrapper = new UpdateWrapper<Position>().lambda()
                .set(Position::getSyncStatus, syncStatus)
                .set(Position::getPositionExt, JsonUtils.obj2json(positionExt))
                .eq(Position::getId, id)
                .eq(Position::getPositionTime, positionTime);
        this.update(updateWrapper);
    }


    /**
     * 获取有位置的数据
     */
    public List<String> listJzIds4Effective(Date startTime, Date endTime) {
        return QueryWrapperConverterPlus.of(positionMapper)
                .list("distinct(jz_id) jz_id", String.class, null, null, q -> {
                    q.ge(Position::getPositionTime, startTime)
                            .le(Position::getPositionTime, endTime)
                            .isNotNull(Position::getLatitude)
                            .isNotNull(Position::getLongitude);
                });
    }


    private void queryWrapper(PositionQueryParamDTO dto, MPJLambdaWrapper<Position> query) {
        if (Boolean.TRUE.equals(dto.getHasPosition())) {
            query.isNotNull(Position::getLatitude)
                    .isNotNull(Position::getLongitude);
        }
        if (Boolean.TRUE.equals(dto.getPositionTimeAsc())) {
            query.orderByAsc(Position::getPositionTime);
        } else {
            query.orderByDesc(Position::getId);
        }

        if (WarningType.VIRTUAL.getCode().equals(dto.getWarningType())) {
            query.select(Position::getPositionExt);
        }
        //数据类型标记：是否是核查记录
        query.isNull(Boolean.FALSE.equals(dto.getDataTypeFlag()), Position::getDataType);
        query.isNotNull(Boolean.TRUE.equals(dto.getDataTypeFlag()), Position::getDataType);

        //系统核查标记：原始记录+核查记录
        query.isNull(Boolean.FALSE.equals(dto.getSysCheckFlag()), Position::getSysCheck);
        query.isNotNull(Boolean.TRUE.equals(dto.getSysCheckFlag()), Position::getSysCheck);

        //是否是纠偏上报记录
        query.gt(Boolean.FALSE.equals(dto.getCorrectFlag()), Position::getCorrectStatus, PositionCorrectStatus.INIT.getCode());
        query.eq(Boolean.TRUE.equals(dto.getCorrectFlag()), Position::getReportType, ReportType.CORRECT.getCode());

    }
}

